package animator.phantom.controller;

/*
    Copyright Janne Liljeblad

    This file is part of Phantom2D.

    Phantom2D is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Phantom2D is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Phantom2D.  If not, see <http://www.gnu.org/licenses/>.
*/

import animator.phantom.exec.*;
import java.util.*;
import java.io.File;

//--- All the state and logic that has something to do with codecs/encoding.
public class CodecController
{
	private static final int CODECD_PROG_TEST_TIMEOUT = 5;

	//--- codec programs.
	public static Vector<String> encodeProgs = new Vector<String>();
	public static Vector<String> availableProgs = new Vector<String>();
	public static Vector<String> notAvailableProgs = new Vector<String>();

	public static final String MENCODER = "mencoder";
	public static final String FFMPEG = "ffmpeg";
	public static final String MPLAYER = "mplayer";
	private static MencoderProg mencoder =  new MencoderProg();
	private static FFMpegProg ffmpeg = new FFMpegProg();
	private static MPlayerProg mplayer = new MPlayerProg();

	//--- Current encode settings, no get/set methods this time.
	public static boolean movieOn;
	public static String movieFileName;
	public static String encProg = null;
	public static String cFormat = null;
	public static String cVCodec = null;
	public static String cACodec = null;
	public static int cVideoBitrate = -10;
	public static int cAudioBitrate = -1;
	public static int encodeQuality = 0;
	public static File inputFile = null;
	public static File inputFolder = null;
	public static File outFolder = null;

	//--- Current import decode settings.
	public static Vector<String> decodeProgs = new Vector<String>();
	public static String decodeProg = null;
	public static String cDecodeFrameFormat = null;
	public static String cDecodeMovie = null;

	public static void testAndInit()
	{
		try
		{
			//--- Run presence tests
			NativeCommandExec ffmpegTest = new NativeCommandExec( "ffmpeg -version", CODECD_PROG_TEST_TIMEOUT );
			NativeCommandExec mencoderTest = new NativeCommandExec( "mencoder -ovc help", CODECD_PROG_TEST_TIMEOUT );
			NativeCommandRunner runner = new NativeCommandRunner();

			runner.addCommand( ffmpegTest );
			runner.addCommand( mencoderTest );
			runner.runCommands();//--- blocks untill all finished.

			//--- These set to encoder and decoder after detection
			String defaultEncProg = null;
			String defaultDecodeProg = null;

			//--- Presence tests results.
			if( mencoderTest.getExitVal() == 0 )
			{
				encodeProgs.add( MENCODER );
				availableProgs.add( MENCODER );
				defaultEncProg = MENCODER;
			}
			else
			{
				notAvailableProgs.add( MENCODER );
			}

			if(  ffmpegTest.getExitVal() == 0 )
			{
				decodeProgs.add( FFMPEG );
				availableProgs.add( FFMPEG );
				defaultDecodeProg = FFMPEG;
			}
			else
			{
				notAvailableProgs.add( FFMPEG );
			}

			//--- Set values from current encoder and decoder program if possible.
			if( defaultEncProg != null )
			{
				setCurrentEncoder( defaultEncProg );
			}
			else
			{
				cFormat = "not available";
				cVCodec = "not available";
				cACodec = "not available";
			}

			if( defaultDecodeProg != null )
			{
				setCurrentDecoder( defaultDecodeProg );
			}

			movieFileName = "movie";
			//--- Info
			printAvailable();

		}
		catch( Exception e )
		{
			System.out.println("Codec test ERROR! ");
			e.printStackTrace();
		}
	}

	//----------------------------------------------------- ENCODING
	public static EncoderProgram currentEncoder()
	{
		if( encProg == null ) return null;

		if( encProg.equals( MENCODER ) ) return mencoder;
		if( encProg.equals( FFMPEG ) ) return ffmpeg;

		return null;
	}

	public static void setCurrentEncoder( String newEncoder )
	{
		encProg = newEncoder;
		String[] formats = getFormats();
		cFormat = formats[ 0 ];

		String[] vCodecs = getVCodecs(cFormat);
		cVCodec = vCodecs[ 0 ];

		String[] aCodecs = getACodecs(cFormat);
		if( aCodecs != null && aCodecs.length > 0 )
			cACodec = aCodecs[ 0 ];
	}

	public static void setDefaultBitRates()
	{
		if( currentEncoder() != null )
		{
			cVideoBitrate = currentEncoder().getDefaultVideoBitRatekbps();
			cAudioBitrate = currentEncoder().getDefaultAudioBitRatekbps();
		}
		else
		{
			cVideoBitrate = 0;
			cAudioBitrate = 0;
		}
	}

	public static String[] getCodecProgs()
	{
		String[] cProgs = new String[ encodeProgs.size() ];
	 	for( int i = 0; i < encodeProgs.size(); i++ )
			cProgs[ i ] = encodeProgs.elementAt( i );
		return cProgs;
	}

	public static String[] getFormats()
	{
		return currentEncoder().getFormats();
	}

	public static String[] getVCodecs( String format )
	{
		return currentEncoder().getFormat( format ).getVCodecs();
	}

	public static String[] getACodecs( String format )
	{
		return currentEncoder().getFormat( format ).getACodecs();
	}
	
	public static String getEncodeCommand()
	{
		return currentEncoder().getCommand();
	}

	private static void printAvailable()
	{
		System.out.println("AVALABLE CODEC PROGRAMS:");
		for( String cprog : availableProgs )
			System.out.println( cprog );
		if( availableProgs.size() == 0 ) System.out.println("none");
	}

	public static String getFrameOptsStr()
	{
		StringBuffer buf = new StringBuffer();

		if( RenderModeController.getTargetFolder() == null )
			buf.append( "no folder set" );
		else buf.append( "/" + RenderModeController.getTargetFolder().getName() );
		buf.append( ", " );
		buf.append( RenderModeController.getFrameName() );
		buf.append( "." );
		buf.append( RenderModeController.getOutFrameType() );
			
		return buf.toString();
	}

	public static String getRenderOptsStr()
	{
		StringBuffer buf = new StringBuffer();
		String[] qualityOpts = { "normal","draft" };
		int currentQuality = RenderModeController.getWriteQuality();
		buf.append( qualityOpts[ currentQuality ] );

		if( movieOn )
		{
			buf.append( ", " );
			buf.append( movieFileName );
			buf.append( "." );
			buf.append( cFormat );
			buf.append( ", " );
			buf.append( cVCodec );
			buf.append( ", " );
			buf.append( Integer.toString(cVideoBitrate) );
			buf.append( "kbps" );
		}
		else
		{
			buf.append( ", no movie created" );
		}

		return buf.toString();
	}

	//----------------------------------------------------- DECODING
	public static EncoderProgram currentDecoder()
	{
		if( decodeProg == null ) return null;

		if( decodeProg.equals( MPLAYER ) ) return mplayer;
		if( decodeProg.equals( FFMPEG ) ) return ffmpeg;

		return null;
	}

	public static void setCurrentDecoder( String newDecoder )
	{
		decodeProg = newDecoder;
		String[] decformats = currentDecoder().getDecodeFrameFormats();
		cDecodeFrameFormat =  decformats[0];
	}

	public static Vector<String> getDecoders(){ return decodeProgs; }

}//end class
